package smallfrench.moteur.biblio;

import smallfrench.moteur.interp.RObjet;

/**
 * Objet contenant des fonctions mathématiques.
 * @author antoine1023
 * TODO : Doit être un {@link RPaquet}.
 */
public class RMath extends RObjet {

	public RMath() {
		super(RClasse.CLASSE);
	}

	//-------------------------------------------

	@Override
	public boolean equals(Object objet) {
		return this == objet;
	}

	//------------------------------------------- Membres

	@Override
	public RObjet getMembre(String nom) {
		try {
			return Membres.valueOf(nom).objet;
		} catch (IllegalArgumentException e) {
			return null;
		}
	}

	//------------------------------------------- Statics

	private enum Membres {
		/**
		 * Retourne la valeur absolue.
		 */
		abs(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {

				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof REntier) {
					REntier n = (REntier)param;
					return new REntier(Math.abs(n.valeur));
				} else if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.abs(n.valeur));
				} else if (param instanceof RDecimal) {
					RDecimal n = (RDecimal)param;
					return new RFlottant(Math.abs(n.enDouble()));
				}
				return RRien.RIEN;
			}
		}),
		cos(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {

				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.cos(n.valeur));

				} else if (param instanceof RDecimal) {
					RDecimal n = (RDecimal)param;
					return new RFlottant(Math.cos(n.enDouble()));
				}
				return RRien.RIEN;
			}
		}),
		sin(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {

				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.sin(n.valeur));

				} else if (param instanceof RDecimal) {
					RDecimal n = (RDecimal)param;
					return new RFlottant(Math.sin(n.enDouble()));
				}
				return RRien.RIEN;
			}
		}),
		tan(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {

				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.tan(n.valeur));

				} else if (param instanceof RDecimal) {
					RDecimal n = (RDecimal)param;
					return new RFlottant(Math.tan(n.enDouble()));
				}
				return RRien.RIEN;
			}
		}),
		arccos(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {

				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.acos(n.valeur));
				}
				return RRien.RIEN;
			}
		}),
		arcsin(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {

				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.asin(n.valeur));
				}
				return RRien.RIEN;
			}
		}),
		arctan(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {
				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.atan(n.valeur));
				}
				return RRien.RIEN;
			}
		}),
		racineCarree(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {
				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.sqrt(n.valeur));
				}
				return RRien.RIEN;
			}
		}),
		puissance(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {
				if (params.length != 2)
					return RRien.RIEN;

				RObjet arg0 = params[0];
				RObjet arg1 = params[1];
				if (arg0 instanceof RFlottant
						&& arg1 instanceof RFlottant) {
					RFlottant n = (RFlottant)arg0;
					RFlottant puissance = (RFlottant)arg1;
					double res = Math.pow(
							n.valeur,
							puissance.valeur);
					return new RFlottant(res);
				}
				return RRien.RIEN;
			}
		}),
		/** Logarithme népérien, de base <i>e</i>. */
		ln(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {
				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.log(n.valeur));
				} else if (param instanceof REntier) {
					REntier n = (REntier)param;
					return new RFlottant(Math.log(n.valeur));
				}
				return RRien.RIEN;
			}
		}),
		/** Logarithme décimal. */
		log10(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {
				if (params.length == 0)
					return RRien.RIEN;

				RObjet param = params[0];
				if (param instanceof RFlottant) {
					RFlottant n = (RFlottant)param;
					return new RFlottant(Math.log10(n.valeur));
				} else if (param instanceof REntier) {
					REntier n = (REntier)param;
					return new RFlottant(Math.log10(n.valeur));
				}
				return RRien.RIEN;
			}
		}),
		/** Flottant aléatoire entre 0,0 et 1,0 */
		flottantAleatoire(new RFonction() {
			@Override
			public RObjet appeler(RObjet moi, RObjet[] params) {
				return new RFlottant(Math.random());
			}
		}),
		/** Valeur approchée du nombre Pi. */
		PI(new RFlottant(Math.PI)),

		/** Valeur approchée de la constante d’Euler. */
		E(new RFlottant(Math.E)),
		;

		private RObjet objet;

		Membres(RObjet objet) {
			this.objet = objet;
		}
	}

	//------------------------------------------- Strings

	@Override
	public RChaine enChaine() {
		return new RChaine("Math");
	}

}
